﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MathLib
{
    public class Vector
    {
        public double[] v;
        private int n;

        public Vector(int num_elements)
        {
            v = new double[num_elements];
            n = num_elements;

            for (int i = 0; i < n; ++i)
            {
                v[i] = 0.0;
            }
        }

        public Vector clone()
        {
            Vector copy = new Vector(N);

            for (int i = 0; i < N; ++i)
            {
                copy.v[i] = v[i];
            }

            return copy;
        }

        public int N
        {
            get { return n; }
        }

        public double X
        {
            get
            {
                if (N > 0)
                {
                    return v[0];
                }
                else
                {
                    throw new IndexOutOfRangeException("X does not exist");
                }
            }

            set
            {
                if (N > 0)
                {
                    v[0] = value;
                }
                else
                {
                    throw new IndexOutOfRangeException("X does not exist");
                }
            }
        }

        public double Y
        {
            get
            {
                if (N > 1)
                {
                    return v[1];
                }
                else
                {
                    throw new IndexOutOfRangeException("Y does not exist");
                }
            }

            set
            {
                if (N > 1)
                {
                    v[1] = value;
                }
                else
                {
                    throw new IndexOutOfRangeException("Y does not exist");
                }
            }
        }

        public double Z
        {
            get
            {
                if (N > 2)
                {
                    return v[2];
                }
                else
                {
                    throw new IndexOutOfRangeException("Z does not exist");
                }
            }

            set
            {
                if (N > 2)
                {
                    v[2] = value;
                }
                else
                {
                    throw new IndexOutOfRangeException("Z does not exist");
                }
            }
        }

        public double Xdot
        {
            get
            {
                if (N > 3)
                {
                    return v[3];
                }
                else
                {
                    throw new IndexOutOfRangeException("Xdot does not exist");
                }
            }

            set
            {
                if (N > 3)
                {
                    v[3] = value;
                }
                else
                {
                    throw new IndexOutOfRangeException("Xdot does not exist");
                }
            }
        }

        public double Ydot
        {
            get
            {
                if (N > 4)
                {
                    return v[4];
                }
                else
                {
                    throw new IndexOutOfRangeException("Ydot does not exist");
                }
            }

            set
            {
                if (N > 4)
                {
                    v[4] = value;
                }
                else
                {
                    throw new IndexOutOfRangeException("Ydot does not exist");
                }
            }
        }

        public double Zdot
        {
            get
            {
                if (N > 5)
                {
                    return v[5];
                }
                else
                {
                    throw new IndexOutOfRangeException("Zdot does not exist");
                }
            }

            set
            {
                if (N > 5)
                {
                    v[5] = value;
                }
                else
                {
                    throw new IndexOutOfRangeException("Zdot does not exist");
                }
            }
        }

        public double mag()
        {
            double sum_sqr = 0.0;

            for (int i = 0; i < N; ++i)
            {
                sum_sqr += v[i] * v[i];
            }

            return Math.Sqrt(sum_sqr);
        }

        public void set_from(Vector a)
        {
            for (int i = 0; i < N; ++i)
            {
                v[i] = a.v[i];
            }
        }

        public Vector unit()
        {
            Vector c = new Vector(N);
            c.set_from(this);

            double c_mag = c.mag();

            for (int i = 0; i < N; ++i)
            {
                c.v[i] /= c_mag;
            }

            return c;
        }

        public Matrix get_matrix_as_col()
        {
            Matrix m = new Matrix(N, 1);

            for (int i = 0; i < N; ++i)
            {
                m.m[i, 0] = v[i];
            }

            return m;
        }

        public Matrix get_matrix_as_row()
        {
            Matrix m = new Matrix(1, N);

            for (int i = 0; i < N; ++i)
            {
                m.m[0, i] = v[i];
            }

            return m;
        }

        public static Vector operator *(Matrix a, Vector v)
        {
            if (a.Cols == v.N)
            {
                Matrix d = a * v.get_matrix_as_col();

                return d.get_col_vector(0);
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public static Vector operator +(Vector a, Vector b)
        {
            if (a.N == b.N)
            {
                Vector c = new Vector(a.N);

                for (int i = 0; i < a.N; ++i)
                {
                    c.v[i] = a.v[i] + b.v[i];
                }

                return c;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public static Vector operator -(Vector a, Vector b)
        {
            if (a.N == b.N)
            {
                Vector c = new Vector(a.N);

                for (int i = 0; i < a.N; ++i)
                {
                    c.v[i] = a.v[i] - b.v[i];
                }

                return c;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public static double operator *(Vector a, Vector b)
        {
            if (a.N == b.N)
            {
                Vector c = new Vector(a.N);

                double dot = 0.0;

                for (int i = 0; i < a.N; ++i)
                {
                    dot += a.v[i] * b.v[i];
                }

                return dot;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public static Vector operator *(double s, Vector a)
        {
            Vector c = new Vector(a.N);

            for (int i = 0; i < a.N; ++i)
            {
                c.v[i] = s * a.v[i];
            }

            return c;
        }
    }
}
